﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace Panda.UI.Runtime
{

    
    public class DefaultLayer : ILayer
    {

        private readonly Dictionary<string, IPage> _registerPages = new ();
        
        private readonly List<IPage> _historyPages = new ();
        private Dictionary<IPage, Queue<IPage>> _pagePoolDic = new();

        public IRouter Router { get; set; }
        public IPage CurrentPage { get; private set; }

        [Obsolete("Remove if not use any more.", true)]
        public bool IsAnimComplete
        {
            get
            {
                foreach (var page in _historyPages)
                {
                    if (page.PageState.IsInAnim())
                    {
                        Debug.Log($"History page: {page.SourcePage} is in anim, PageState: {page.PageState}");
                        return false;
                    }
                }

                foreach (var kvp in _pagePoolDic)
                {
                    foreach (var page in kvp.Value)
                    {
                        if (page.PageState.IsInAnim())
                        {
                            Debug.Log($"Pooled page: {page.SourcePage} is in anim, PageState: {page.PageState}");
                            return false;
                        }
                    }
                }

                return true;
            }
        }

        public void Register(string pageId, IPage page)
        {
            _registerPages[pageId] = page;
            _pagePoolDic[page] = new Queue<IPage>();
            _pagePoolDic[page].Enqueue(page);
            page.SourcePage = page;
            
            page.Load();
        }

        public void ReLaunch(string pageId, object data, Action success, Action fail, Action complete)
        {
            for (int i = _historyPages.Count - 1; i >= 0; i--)
            {
                var lastPage = _historyPages[i];
                if ((lastPage.PageState & PageState.Hided) != 0)
                {
                    lastPage.Hide();
                    _pagePoolDic[lastPage.SourcePage].Enqueue(lastPage);
                }
            }
            _historyPages.Clear();
            
            NavigateTo(pageId, data, success, fail, complete, false);
        }

        public void RedirectTo(string pageId, object data, Action success, Action fail, Action complete)
        {
        }

        public void NavigateTo(string pageId, object data, Action success, Action fail, Action complete, bool createNewIfInHistory)
        {
            if (_registerPages.TryGetValue(pageId, out IPage regPage) == false)
            {
                Debug.LogWarning($"Cannot navigate to page: {pageId},.");
                fail?.Invoke();
                complete?.Invoke();
                return;
            }

            IPage newPage = null;
            if (createNewIfInHistory == false)
            {
                if (_historyPages.Count != 0)
                {
                    var prePage = _historyPages[^1];
                    if (prePage.SourcePage == regPage)
                    {
                        Debug.LogWarning("Page already opened!");
                        fail?.Invoke();
                        complete?.Invoke();
                        return;
                    }

                    for (int i = _historyPages.Count - 2; i >= 0; i--)
                    {
                        var item = _historyPages[i];
                        if (item.SourcePage == regPage)
                        {
                            newPage = item;
                            _historyPages.RemoveAt(i);
                            break;
                        }
                    }
                }
            }

            if (newPage == null && _pagePoolDic[regPage].TryDequeue(out newPage) == false)
            {
                newPage = regPage.Clone();
                newPage.SourcePage = regPage;
                newPage.Router = regPage.Router;
                newPage.Load();
            }

            if (_historyPages.Count != 0)
            {
                if (newPage.IsPopup == false)
                {
                    for (int i = _historyPages.Count - 1; i >= 0; i--)
                    {
                        var historyPage = _historyPages[i];
                        if (historyPage.PageState.HasFlag(PageState.Showed))
                        {
                            historyPage.Hide();
                        }
                    }
                }
                else
                {
                    var prePage = _historyPages[^1];
                    prePage.Cover();
                }
            }

            newPage.Data = data;
            newPage.Show(false);
            _historyPages.Add(newPage);

            CurrentPage = newPage;

            success?.Invoke();
            complete?.Invoke();
        }

        public void NavigateBack(Action success, Action fail, Action complete)
        {
            if (_historyPages.Count <= 1)
            {
                Debug.LogError("Cannot navigate back, no pages in history!");
                fail?.Invoke();
                complete?.Invoke();
                return;
            }

            if (_historyPages.Count == 0)
            {
                Debug.LogWarning($"Cannot navigate back! , HistoryPages: {_historyPages.Count}");
                fail?.Invoke();
                complete?.Invoke();
                return;
            }

            var lastIndex = _historyPages.Count - 1;
            var lastPage = _historyPages[lastIndex];
            _historyPages.RemoveAt(lastIndex);

            var lastPageIsPopup = lastPage.IsPopup;
            lastPage.Hide();
            _pagePoolDic[lastPage.SourcePage].Enqueue(lastPage);

            if (_historyPages.Count != 0)
            {
                var prePage = _historyPages[^1];
                if (lastPageIsPopup == false)
                {
                    prePage.Show(true);
                }
                else
                {
                    prePage.Recover();
                }
                
                CurrentPage = prePage;
            }
            else
            {
                CurrentPage = null;
            }

            success?.Invoke();
            complete?.Invoke();
        }
    }
}